use std::ops::BitAnd;

use super::{PiecesType, TimeRange};

impl BitAnd for TimeRange {
    type Output = Self;

    fn bitand(self, rhs: Self) -> Self::Output {
        Self(self.0 & rhs.0)
    }
}

impl TimeRange {
    pub fn is_conflict(&self, rhs: &Self) -> bool {
        (self.0 ^ rhs.0) != 0
    }

    pub fn get_clear_time(&self) -> u64 {
        ((self.0 >> 1) | self.0) ^ self.0
    }
}

impl TimeRange {
    fn bitmap_to_array(mut bitmap: u64) -> [bool; 64] {
        let mut res = [false; 64];
        let mut idx = 0;

        while bitmap > 0 {
            if bitmap > (u64::MAX >> 1) {
                res[idx] = true
            }

            bitmap = bitmap << 1;
            idx += 1;
        }

        res
    }

    pub fn to_status_vec(admin_ban: TimeRange, booked: Vec<TimeRange>) -> [PiecesType; 64] {
        let mut res = [PiecesType::Available; 64];
        TimeRange::bitmap_to_array(admin_ban.0)
            .into_iter()
            .enumerate()
            .filter(|(_idx, ok)| *ok)
            .for_each(|(idx, _)| res[idx] = PiecesType::NotForBooking);

        booked.into_iter().for_each(|tr| {
            TimeRange::bitmap_to_array(tr.0)
                .into_iter()
                .enumerate()
                .filter(|(_, b)| *b)
                .for_each(|(idx, _)| res[idx] = PiecesType::Booked);
            let clear_idx = tr.get_clear_time().leading_zeros() as usize;
            res[clear_idx] = PiecesType::ForClean;
        });

        res
    }
}
#[cfg(test)]
mod test {
    use crate::utils::time_using::TimeRange;

    static BAN: u64 =
        0b_1100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0011_1111;
    static BOOKED: u64 =
        0b_0000_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;
    static CLEAN_TIME: u64 =
        0b_0000_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000;

    #[test]
    fn test_clean_time() {
        let t = TimeRange(BOOKED);
        let clean = t.get_clear_time();

        println!("{clean:064b}");

        assert_eq!(clean, CLEAN_TIME);
    }

    #[test]
    fn test_time_color() {
        let t = TimeRange(BOOKED);
        let b = TimeRange(BAN);

        let v = TimeRange::to_status_vec(b, vec![t]);

        for c in v {
            let c = match c {
                crate::utils::time_using::PiecesType::NotForBooking => 'X',
                crate::utils::time_using::PiecesType::Booked => '-',
                crate::utils::time_using::PiecesType::ForClean => '*',
                crate::utils::time_using::PiecesType::Available => '#',
            };
            print!("{c}")
        }
    }
}
